package com.huabo.weixin;

import com.alibaba.fastjson.JSONObject;
import com.huabo.file.FileOperation;
import com.huabo.utils.FastJsonUtils;
import com.huabo.utils.FileUtils;
import com.huabo.utils.SHA1Utils;
import com.huabo.weixin.model.*;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.data.redis.core.StringRedisTemplate;

import java.io.File;
import java.io.FileNotFoundException;
import java.util.*;
import java.util.concurrent.TimeUnit;

import static com.alibaba.fastjson.JSON.parseObject;

/**
 * 微信开放API
 * Created by Jackie Liu on 2017/8/19.
 */
public class WXOpenApi implements InitializingBean {

    private static final Logger log = Logger.getLogger(WXOpenApi.class);
    private StringRedisTemplate redisTemplate;
    private FileOperation fileOperation;
    private String appId;
    private String appSecret;

    //access_token缓存在redis中的key值
    private static final String ACCESS_TOKEN_CACHE_KEY = "_access_token_cache_key_";
    //jsapi_ticket缓存在redis中的key值
    private static final String JS_API_TICKET_CACHE_KEY = "_js_api_ticket_cache_key_";

    /**
     * 获取基础Api调用的access_token(与网页授权后的access_token不同，由于有调用频次限制需全局缓存)
     * {"access_token":"lwx7UbbnfzS14zheH7oFy06CCQmpwAsUCRxEKJwYKFY5Y6O-2Bud6dT1HKwjSLfLMDl2xbdIVvFge9D91TKJhzC2OSXpxQzPEGXYK-tTGVHRxuPXwyU57yY3jIKicugQCLAfAJAUDS","expires_in":7200}
     *
     * @return
     */
    private String getBaseAccessToken() {
        String accessToken = redisTemplate.opsForValue().get(ACCESS_TOKEN_CACHE_KEY);
        if (StringUtils.isNotEmpty(accessToken)) {
            return accessToken;
        }
        String url = String.format("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s", appId, appSecret);
        String result = WXHttpHelper.sendGet(url);
        //System.out.println("result = " + result);
        if (isError(result)) {
            log.info(String.format("调用微信接口错误(获取access_token)，错误信息为：%s；请求URL：%s", result, url));
            return null;
        }
        WXAccessToken wxAccessToken = parseObject(result, WXAccessToken.class);
        redisTemplate.opsForValue().set(ACCESS_TOKEN_CACHE_KEY, wxAccessToken.getAccess_token(), wxAccessToken.getExpires_in() - 10, TimeUnit.SECONDS);
        return wxAccessToken.getAccess_token();
    }

    /**
     * 获取openid
     *
     * @param code
     * @return
     */
    public WXOpenId getOpenId(String code) {
        String url = String.format("https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code", appId, appSecret, code);
        String result = WXHttpHelper.sendGet(url);
        //System.out.println("result = " + result);
        if (isError(result)) {
            log.info(String.format("调用微信接口错误(获取openid)，错误信息为：%s；请求URL：%s", result, url));
            return null;
        }
        return parseObject(result, WXOpenId.class);
    }

    /**
     * 获取微信用户信息
     *
     * @param openId 普通用户的标识，对当前公众号唯一
     */
    public WXUser getUser(String openId) {
        String accessToken = getBaseAccessToken();
        String url = String.format("https://api.weixin.qq.com/cgi-bin/user/info?access_token=%s&openid=%s&lang=zh_CN", accessToken, openId);
        String result = WXHttpHelper.sendGet(url);
        //System.out.println("result = " + result);
        if (isError(result)) {
            log.info(String.format("调用微信接口错误(获取微信用户信息)，错误信息为：%s；请求URL：%s", result, url));
            return null;
        }
        return parseObject(result, WXUser.class);
    }

    /**
     * 下载资源(图片，声音)
     *
     * @param tempDir 临时保存目录
     * @param mediaId 资源id
     * @return 文件路径
     */
    public WXFile getMedia(String tempDir, String mediaId) {
        String accessToken = getBaseAccessToken();
        String url = String.format("https://api.weixin.qq.com/cgi-bin/media/get?access_token=%s&media_id=%s", accessToken, mediaId);
        String tempFilePath = WXHttpHelper.download(tempDir, url);
        return transferFile(tempFilePath);
    }

    private WXFile transferFile(String tempFilePath) {
        try {
            if (StringUtils.isNotEmpty(tempFilePath)) {
                File file = new File(tempFilePath);
                String p = fileOperation.save(file);

                WXFile wxFile = new WXFile();
                wxFile.setPath(p);
                wxFile.setSize(file.length());
                wxFile.setName(file.getName());

                String[] pics = {"jpg", "png", "jpeg", "gif", "bmp"};
                String extName = FilenameUtils.getExtension(file.getName()).toLowerCase();
                if (Arrays.asList(pics).indexOf(extName) >= 0) {
                    wxFile.setType("pic");
                } else {
                    wxFile.setType(extName);
                }
                return wxFile;
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } finally {
            FileUtils.deleteFile(tempFilePath);
        }
        return null;
    }

    /**
     * jsapi_ticket是公众号用于调用微信JS接口的临时票据(全局缓存)
     * {"errcode":0,"errmsg":"ok","ticket":"kgt8ON7yVITDhtdwci0qeaRDE7cg5i3hLlOxH_ITUALF96X08ZJ8q2FuvqEAeJn21nUN4xgllGCiGJXVlFb9Qw","expires_in":7200}
     */
    public String getJsapi_ticket() {
        String ticket = redisTemplate.opsForValue().get(JS_API_TICKET_CACHE_KEY);
        if (StringUtils.isNotEmpty(ticket)) {
            return ticket;
        }
        String accessToken = getBaseAccessToken();
        String url = String.format("https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=%s&type=jsapi", accessToken);
        String result = WXHttpHelper.sendGet(url);
        //System.out.println("result = " + result);
        WXJsTicket wxJsTicket = parseObject(result, WXJsTicket.class);
        if (wxJsTicket.getErrcode() != 0) {
            log.info(String.format("调用微信接口错误(jsapi_ticket)，错误信息为：%s；请求URL：%s", result, url));
            return null;
        }
        redisTemplate.opsForValue().set(JS_API_TICKET_CACHE_KEY, wxJsTicket.getTicket(), wxJsTicket.getExpires_in() - 10, TimeUnit.SECONDS);
        return wxJsTicket.getTicket();
    }

    /**
     * 获取二维码票据
     *
     * @param sceneId 场景id
     * @return
     */
    public WXQRCodeTicket getQRCodeTicket(long sceneId) {
        String accessToken = getBaseAccessToken();
        String url = String.format("https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=%s", accessToken);
        String json = String.format("{\"action_name\": \"QR_LIMIT_SCENE\", \"action_info\": {\"scene\": {\"scene_id\": %d}}}", sceneId);
        String result = WXHttpHelper.sendJson(url, json);
        if (StringUtils.isEmpty(result)) {
            return null;
        }
        WXQRCodeTicket wxqrCodeTicket = parseObject(result, WXQRCodeTicket.class);
        return wxqrCodeTicket;
    }

    /**
     * 拉取场景二维码图片
     *
     * @param tempDir      临时文件夹
     * @param qrCodeTicket 二维码票据
     * @return
     */
    public WXFile getQRCodeFile(String tempDir, String qrCodeTicket) {
        String url = String.format("https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=%s", qrCodeTicket);
        String tempFilePath = WXHttpHelper.download(tempDir, url);
        return transferFile(tempFilePath);
    }

    /**
     * 获取签名
     *
     * @param noncestr  随机字符串
     * @param timestamp 时间戳
     * @return
     */
    public String getSignature(String noncestr, long timestamp, String url) {
        String jsapi_ticket = getJsapi_ticket();
        String signature = String.format("jsapi_ticket=%s&noncestr=%s&timestamp=%d&url=%s", jsapi_ticket, noncestr, timestamp, url);
        return SHA1Utils.encode(signature);
    }

    private boolean isError(String result) {
        if (StringUtils.isEmpty(result)) {
            return true;
        }
        JSONObject json = parseObject(result);
        if (json.getString("errcode") == null
                || json.getInteger("errcode") == 0) {
            return false;
        }
        return true;
    }

    /**
     * 创建自定义菜单
     * @param menuJsonStr 自定义菜单json
     * @return 是否创建成功
     */
    public boolean createMenu(String menuJsonStr) {
        //String accessToken = getBaseAccessToken();
        String accessToken = "91th5pjX5sbaD65luc5l3dGQaRE8dbTl1ZGOnI_cjRxtQxwue0lGHF3zrhgHd45sF-h7NiDosRF5AbKz6M6C_yCub9KT4IRuOAuaNNdyRydrl4a4grYOHbeOCuExam4ZTNBeAFAICQ";
        String url = String.format("https://api.weixin.qq.com/cgi-bin/menu/create?access_token=%s", accessToken);
        String result = WXHttpHelper.sendJson(url, menuJsonStr);
        System.out.println(result);
        if (isError(result)) {
            return false;
        }
        return true;
    }

    /**
     * 获取自定义菜单
     * @return
     */
    public String getMenus() {
        //String accessToken = getBaseAccessToken();
        String accessToken = "91th5pjX5sbaD65luc5l3dGQaRE8dbTl1ZGOnI_cjRxtQxwue0lGHF3zrhgHd45sF-h7NiDosRF5AbKz6M6C_yCub9KT4IRuOAuaNNdyRydrl4a4grYOHbeOCuExam4ZTNBeAFAICQ";
        String url = String.format("https://api.weixin.qq.com/cgi-bin/menu/get?access_token=%s", accessToken);
        String result = WXHttpHelper.sendGet(url);
        return result;
    }

    /**
     * 删除自定义菜单
     * @return 是否删除成功
     */
    public boolean removeMenu() {
        //String accessToken = getBaseAccessToken();
        String accessToken = "91th5pjX5sbaD65luc5l3dGQaRE8dbTl1ZGOnI_cjRxtQxwue0lGHF3zrhgHd45sF-h7NiDosRF5AbKz6M6C_yCub9KT4IRuOAuaNNdyRydrl4a4grYOHbeOCuExam4ZTNBeAFAICQ";
        String url = String.format("https://api.weixin.qq.com/cgi-bin/menu/delete?access_token=%s", accessToken);
        String result = WXHttpHelper.sendGet(url);
        System.out.println(result);
        if (isError(result)) {
            log.info(String.format("调用微信接口错误(删除自定义菜单)，错误信息为：%s；请求URL：%s", result, url));
            return false;
        }
        return true;
    }

    /**
     *
     * @param openId
     * @param message
     * @return 是否发送成功
     */

    /**
     * 发送客服消息
     * @param openId 用户的openid
     * @param title 消息标题
     * @param link 消息详情链接
     * @param message 消息内容，换行用\n
     * @return 是否推送成功
     */
    public boolean sendMessage(String openId, String title, String link, String message) {
        String accessToken = getBaseAccessToken();
        String url = String.format("https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=%s", accessToken);
        String str = String.format("{\"touser\":\"%s\",\"msgtype\":\"news\",\"news\":{\"articles\":[{\"title\":\"%s\",\"description\":\"%s\",\"url\":\"%s\"}]}}", openId, title, message, link);
        //log.info("############## str = " + str);
        //String str = String.format("{\"touser\":\"%s\",\"msgtype\":\"text\",\"text\":{\"content\":\"%s\"}}", openId, message);
        String result = WXHttpHelper.sendJson(url, str);
        //log.info("############## result = " + result);
        if (StringUtils.isEmpty(result)) {
            return false;
        }
        return true;
    }

    @Override
    public void afterPropertiesSet() throws Exception {

    }

    public String getAppId() {
        return appId;
    }

    public void setAppId(String appId) {
        this.appId = appId;
    }

    public String getAppSecret() {
        return appSecret;
    }

    public void setAppSecret(String appSecret) {
        this.appSecret = appSecret;
    }

    public StringRedisTemplate getRedisTemplate() {
        return redisTemplate;
    }

    public void setRedisTemplate(StringRedisTemplate redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    public FileOperation getFileOperation() {
        return fileOperation;
    }

    public void setFileOperation(FileOperation fileOperation) {
        this.fileOperation = fileOperation;
    }

    public static void main(String[] args) {
        WXOpenApi api = new WXOpenApi();
        //api.setAppId("wxadb2fefa66525a40");
        //api.setAppSecret("ac1ccf9c2fae1ee3b49b251533551d14");

        String  accessToken = "U3MT7YJ8P7CgkatUm8LGdgWvKCcbyd_TguQtrgtrFrqBmS-t5EfYD38InJsNyoGu4KS9f2kRijUqQjerER8fa-ocMF7UqVn8kpuLs6JVMV34tUSHjpnxaow4ZmNq285TBPGeAJAMAR";
        //api.getQRCodeFile("E:/files/", "gQGV8TwAAAAAAAAAAS5odHRwOi8vd2VpeGluLnFxLmNvbS9xLzAyZFhacmhCUkRmMzExMDAwMGcwM04AAgQ-wp9ZAwQAAAAA");
        //api.getJsapi_ticket("lwx7UbbnfzS14zheH7oFy06CCQmpwAsUCRxEKJwYKFY5Y6O-2Bud6dT1HKwjSLfLMDl2xbdIVvFge9D91TKJhzC2OSXpxQzPEGXYK-tTGVHRxuPXwyU57yY3jIKicugQCLAfAJAUDS");

        Map<String, Object> buttonMap = new HashMap<>();
        List<Map<String, Object>> buttonList = new ArrayList<>();
        buttonMap.put("button", buttonList);

        Map<String, Object> firstButton = new HashMap<>();
        firstButton.put("type", "view");
        firstButton.put("name", "江淮义警");
        firstButton.put("url", "https://open.weixin.qq.com/connect/oauth2/authorize?appid=wxadb2fefa66525a40&redirect_uri=http%3A%2F%2Fjhyj.ahga.gov.cn%2Fwx%2Fcallback%2Findex.htm&response_type=code&scope=snsapi_base&state=123#wechat_redirect");
        buttonList.add(firstButton);

        Map<String, Object> secondButton = new HashMap<>();
        //secondButton.put("type", "click");
        secondButton.put("name", "服务平台");
        buttonList.add(secondButton);

        List<Map<String, String>> subButtonList = new ArrayList<>();
        Map<String, String> subButton = new HashMap<>();
        subButton.put("type", "view");
        subButton.put("name", "皖警e网通");
        subButton.put("url", "https://open.weixin.qq.com/connect/oauth2/authorize?appid=wxadb2fefa66525a40&redirect_uri=http%3A%2F%2Fjhyj.ahga.gov.cn%2Fwx%2Fcallback%2Fdownload.htm&response_type=code&scope=snsapi_base&state=123#wechat_redirect");
        subButtonList.add(subButton);
        secondButton.put("sub_button", subButtonList);

        subButton = new HashMap<>();
        subButton.put("type", "view");
        subButton.put("name", "安徽警方");
        subButton.put("url", "https://m.weibo.cn/p/1005051419172372");
        subButtonList.add(subButton);

        subButton = new HashMap<>();
        subButton.put("type", "view");
        subButton.put("name", "警探");
        subButton.put("url", "https://vzan.com/f/s-902490?typeId=0&auth_time=636421312291606534");
        subButtonList.add(subButton);

        subButton = new HashMap<>();
        subButton.put("type", "view");
        subButton.put("name", "高速违法举报");
        subButton.put("url", "http://www.ahedt.gov.cn/uploadvio/h5/");
        subButtonList.add(subButton);

        subButton = new HashMap<>();
        subButton.put("type", "view");
        subButton.put("name", "禁毒在线举报");
        subButton.put("url", "http://ahjd.gstai.com/mobile/online_report.php?code=011VAGWM1b1a621QVzXM1a4vWM1VAGWF&state=xt_common_state");
        subButtonList.add(subButton);

        Map<String, Object> thridButton = new HashMap<>();
        thridButton.put("type", "view");
        thridButton.put("name", "个人中心");
        thridButton.put("url", "https://open.weixin.qq.com/connect/oauth2/authorize?appid=wxadb2fefa66525a40&redirect_uri=http%3A%2F%2Fjhyj.ahga.gov.cn%2Fwx%2Fcallback%2Fmine.htm&response_type=code&scope=snsapi_base&state=123#wechat_redirect");
        buttonList.add(thridButton);

        String menuJsonStr = FastJsonUtils.objToJson(buttonMap);
        //boolean result = api.removeMenu();
        //System.out.println(result);
        System.out.println(menuJsonStr);
        //api.sendMessage("oNWfDwTpa2CjuNzZGBj88dNyCgaw", "message", accessToken, "");
        boolean result = api.createMenu(menuJsonStr);
        //String result = api.getMenus();
        System.out.println(result);

        //api.getMedia("E:/files/", "9zDeaWbUuH-_3KccoP7I_Wq8yUqmJq2RD6nfY6YebJOSHzvJQdzLqa-yvc5-ajkA");
    }
}
